package com.sc.demo.cfg;

import com.sc.demo.service.MyUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

/**
 * @version 1.0
 * @Author: 许啸林
 * @Date: 2021/6/22 12:33
 */
@Configuration
public class SercurityCfg extends WebSecurityConfigurerAdapter {
    @Autowired
    private MyUserDetailService myUserDetailService;

    @Autowired
    private DataSource dataSource;

    /**
     * 注入JdbcTokenRepositoryImpl 对象,该对象封装了记住我功能对数据库的持久化操作,配置数据源
     * @return
     */
    @Bean
    PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        // 配置数据源
        jdbcTokenRepository.setDataSource(dataSource);
        // 启动服务时创建表
        //jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }

    /**
     * 设置获取用户方式
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailService);
    }

    /**
     * 自定义用户登录放行规则
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 配置自定义403权限错误页面
        http.exceptionHandling().accessDeniedPage("/unAuth.html");
        http.formLogin()
                // 自定义登录页面
                .loginPage("/MyLogin.html")
                // 自定义登录表单提交地址, 登录过程由security实现
                .loginProcessingUrl("/user/login")
                // 登录成功返回路径
                .defaultSuccessUrl("/loginSuccess.html").permitAll()
              // 设置放行路径
             .and().authorizeRequests().antMatchers("/", "/test/hello", "/user/login").permitAll()
             //基于权限的访问控制 hasAuthority必须含有某个角色权限
             //.antMatchers("/test/hello").hasAuthority("list")
             //基于权限的访问控制 hasAnyAuthority必须含有配置放行的任意一个角色权限
             //.antMatchers("/test/hello").hasAnyAuthority("admin","manager")
             // 基于角色的访问控制 hasRole,hasAnyRole
             // userDetailService 需要添加角色前缀ROLE_,  String anyAuthorities = StringUtils.arrayToDelimitedString(authorities, "','ROLE_");
             .antMatchers("/test/hello").hasAnyRole("sale")
             .antMatchers("/test/unauthTest").hasAnyRole("manage")
             .anyRequest().authenticated()
             // 用户注销 logoutUrl为注销请求地址,注销由security实现,注销成功后跳转到logoutSuccessUrl 配置路径
             .and().logout().logoutUrl("/loginOut").logoutSuccessUrl("/MyLogin.html")
             // 记住我设置
             .and().rememberMe()
                   // 设置配置的jdbcTokenRepository
                   .tokenRepository(persistentTokenRepository())
                   // 设置有效时间
                   .tokenValiditySeconds(3600)
                   // 设置自定义用户信息验证类
                   .userDetailsService(userDetailsService())
             .and().csrf().disable();

    }

    /**
     * 加密规则
     * @return
     */
    @Bean
    PasswordEncoder passwordEncoder() {
        return  new BCryptPasswordEncoder();
    }

}
